#include "audio_encoder.h"
#include "driver_gpio.h"
#include <speex/speex.h>
#include "adpcm-pcm.h"

Audio_Encode_t audio_encode = {0};

uint16_t task_id_audio_encode = TASK_ID_NONE;


static volatile uint16_t  speak_len = 0;

void *encoder_state = NULL;
// Initialization of the structure that holds the bits
SpeexBits bits;


ima_adpcm_state_t* state = NULL;



static uint8_t data[AUDIO_FRAME_LEN] = {0};
static uint8_t encode_data[AUDIO_FRAME_LEN] = {0};
extern void notify_data(uint8_t *data,uint8_t len);

 __attribute__((section("ram_code"))) int audio_encode_task(os_event_t *param)
{
	uint16_t wait_send_size = 0,wait_act_len = 0;
	uint16_t buffer_size = 0,act_len = 0;
	
    switch(param->event_id)
    {
			case ENCODER_REMAIN_EVENT:
				//printf("wait encode %d\r\n",y_ringbuf_get_used_size(audio_encode.pcm_in_ringbuffer));
				wait_act_len =  y_ringbuf_get_used_size(audio_encode.encoder_out_ringbuffer);
				if(wait_act_len>=AUDIO_FRAME_LEN)
				{
					printf("middle frame %d\r\n",wait_act_len);
					wait_act_len = y_ringbuf_read_clear(audio_encode.encoder_out_ringbuffer,encode_data,AUDIO_FRAME_LEN);
					notify_data(encode_data,wait_act_len);
					msg_send_remain_event();
				}else
				{
					printf("last frame %d\r\n",wait_act_len);
					wait_act_len = y_ringbuf_read_clear(audio_encode.encoder_out_ringbuffer,encode_data,AUDIO_FRAME_LEN);
					notify_data(encode_data,wait_act_len);
					
					audio_encode_current_frame_reset();
					
					audio_encode_current_send_frame_reset();
				}
				
				break;
        case ENCODER_EVENT:
				audio_encode.status = ENCODER_STATE_BUSY;
				wait_act_len =  y_ringbuf_get_used_size(audio_encode.encoder_out_ringbuffer);
				
				if(wait_act_len>=(AUDIO_FRAME_LEN))
				{
					wait_act_len = y_ringbuf_read_clear(audio_encode.encoder_out_ringbuffer,encode_data,AUDIO_FRAME_LEN);
					
					notify_data(encode_data,wait_act_len);
				}
			
			//printf("audio_encoder_start\r\n");
				//memset(data,0,sizeof(data));
				//memset(data,0,sizeof(encode_data));
				//buffer_size = get_audio_encoder_valid_size();
				//if(buffer_size>=AUDIO_FRAME_LEN)
	{
		
		//printf("1 heap size %d\r\n",os_get_free_heap_size());	
			//speex_bits_reset(&bits);
			act_len = y_ringbuf_read_clear(audio_encode.pcm_in_ringbuffer,data,AUDIO_FRAME_LEN);
		
			//Encode frame
		#if 0
			 speex_bits_reset(&bits);
        speex_encode_int(encoder_state, (short *)data, &bits);
				//speex_bits_nbytes(&bits);
        // Copy the bits to an array of char that can be written
        size_t s = speex_bits_write(&bits, (char *)encode_data, AUDIO_FRAME_LEN);
				printf("2 heap size %d\r\n",os_get_free_heap_size());	
				printf("src size %d,encode size %d\r\n",act_len,s);
		#else
		
		int len = ima_adpcm_encode(state, encode_data,(uint16_t*)data, act_len/2);
		#include "driver_uart.h"
//		for(int i = 0;i<AUDIO_FRAME_LEN/4;i++)
//		{
//				printf("%02x",encode_data[i]);
//		}
//		
//		 printf("\r\n");
//src size %d,Encode data length is:%d\r\n",act_len, len);
	
		
		#endif
		
		if(y_ringbuf_write(audio_encode.encoder_out_ringbuffer,encode_data,len) == false)
		{
			printf("write encode data fail\r\n");
		}
		

			audio_encode.status = ENCODER_STATE_IDLE;
	}
	
			
					
				//printf("event\r\n");
				//audio_encoder_start();
        //audio_encoder_next_frame_handler( (struct pcm_data_t *)(param->param) );
         break;
    }
    return EVT_CONSUMED;
}


void audio_encoder_init(void)
{
	audio_encode.status = ENCODER_STATE_IDLE;
	audio_encode.status1 = ENCODER_STATE_IDLE;
	
	audio_encode.pcm_in_ringbuffer = y_ringbuf_create(RINGBUFFER_LEN);  
	audio_encode.encoder_out_ringbuffer = y_ringbuf_create(RINGBUFFER_LEN);  
	
	task_id_audio_encode = os_task_create(audio_encode_task);
	printf("task_id_audio_encode %d\r\n",task_id_audio_encode);

	
printf("heap size %d\r\n",os_get_free_heap_size());
//encoder_state = speex_encoder_init(&speex_nb_mode);
printf("heap size %d\r\n",os_get_free_heap_size());	
	
// Set quality to 8 (15 kbps)
		#if 0
			uint32_t frame_size= 0;
				
				// 设置编码器和解码器参数
				int sample_rate = 8000;
				int quality = 4;
			speex_encoder_ctl(encoder_state, SPEEX_SET_SAMPLING_RATE, &sample_rate);
				
				speex_encoder_ctl(encoder_state,SPEEX_GET_FRAME_SIZE,&frame_size);
					speex_encoder_ctl(encoder_state, SPEEX_SET_QUALITY, &quality);
				printf("frame_size =%d\r\n",frame_size);
					speex_bits_init(&bits);
		#else
		
			/*Init adpcm*/
		state = ima_adpcm_init(state, IMA_ADPCM_DVI4);
		#endif
}



 __attribute__((section("ram_code"))) void audio_encoder_start(void)
{
	//printf("audio_encoder_start\r\n");
	uint16_t buffer_size = 0,act_len = 0;
	memset(data,0,sizeof(data));
	memset(data,0,sizeof(encode_data));
	//buffer_size = get_audio_encoder_valid_size();
	//if(buffer_size>=AUDIO_FRAME_LEN)
	{
			audio_encode.status = ENCODER_STATE_BUSY;
		printf("1 heap size %d\r\n",os_get_free_heap_size());	
			//speex_bits_reset(&bits);
			act_len = y_ringbuf_read_clear(audio_encode.pcm_in_ringbuffer,data,AUDIO_FRAME_LEN);
		
			//Encode frame
		#if 0
        speex_encode_int(encoder_state, (short *)data, &bits);
				//speex_bits_nbytes(&bits);
        // Copy the bits to an array of char that can be written
        size_t s = speex_bits_write(&bits, (char *)encode_data, AUDIO_FRAME_LEN);
				printf("2 heap size %d\r\n",os_get_free_heap_size());	
				printf("src size %d,encode size %d\r\n",act_len,s);
		#else
		
		int len = ima_adpcm_encode(state, encode_data,(uint16_t*)data, act_len);
		printf("Encode data length is:%d\r\n", len);
	
		
		#endif
			audio_encode.status = ENCODER_STATE_IDLE;
	}
	
}

void audio_encoder_stop(void)
{
	
}

void ringbuffer_reset()
{
	y_ringbuf_reset(audio_encode.pcm_in_ringbuffer);
}


 __attribute__((section("ram_code"))) bool audio_encoder_src_input(uint8_t*data,uint16_t len)
{
		return y_ringbuf_write(audio_encode.pcm_in_ringbuffer,data, len);
}

 __attribute__((section("ram_code"))) uint16_t get_audio_encoder_valid_size()
{
	return y_ringbuf_get_used_size(audio_encode.pcm_in_ringbuffer);
}



 __attribute__((section("ram_code"))) bool get_audio_encoder_is_busy(void)
{
		if(audio_encode.status == ENCODER_STATE_BUSY)
			return true;
		else
			return false;
}


 __attribute__((section("ram_code"))) bool get_num_audio_encoder_is_busy(uint8_t num)
{
	if(num == 0)
	{
			if(audio_encode.status == ENCODER_STATE_BUSY)
			return true;
		else
			return false;
	}	else if(num == 1)
	{
			if(audio_encode.status1 == ENCODER_STATE_BUSY)
			return true;
		else
			return false;
	}

}


void audio_encode_current_frame_reset()
{
	audio_encode.current_frame_index = 0;
}

void audio_encode_current_frame_add()
{
	audio_encode.current_frame_index+=1;
}

uint32_t audio_encode_get_current_frame()
{
	return audio_encode.current_frame_index;
}



void audio_encode_current_send_frame_add()
{
	audio_encode.current_send_frame_index+=(1)*4;
}

uint32_t audio_encode_get_current_send_frame()
{
	return audio_encode.current_send_frame_index;
}

void audio_encode_current_send_frame_reset()
{
	audio_encode.current_send_frame_index = 0;
}

void audio_write_to_ringbuffer(uint8_t *data,int len)
{
	y_ringbuf_write(audio_encode.pcm_in_ringbuffer,data,len);
	speak_len+=len;
}


uint16_t audio_read_to_ringbuffer(uint8_t *read,int len)
{
	int read_len = y_ringbuf_read_clear(audio_encode.pcm_in_ringbuffer,read,len);
	
	if((speak_len == 0)||(speak_len<len))
	{
		return read_len;
	}
	 speak_len-=len;
	
	return read_len;
}


uint16_t get_speak_len()
{
	return speak_len;
}



 __attribute__((section("ram_code"))) void msg_post_encode_handler()
{
	//printf("%s\r\n",__FUNCTION__);
	os_event_t event={0};
	event.event_id = ENCODER_EVENT;
	event.src_task_id = TASK_ID_NONE;
	event.param = NULL;
	event.param_len = 0;
	os_msg_post(task_id_audio_encode,&event);
}


void msg_send_remain_event()
{
							os_event_t event={0};
							event.event_id = ENCODER_REMAIN_EVENT;
							event.src_task_id = TASK_ID_NONE;
							event.param = NULL;
							event.param_len = 0;
							os_msg_post(task_id_audio_encode,&event);
}



/**
  * @brief  Ovveride the _speex_putc function of the speex library
  * @param  None
  * @retval : None
  */
void _speex_putc(int ch, void *file)
{
  while(1)
  {
  };
}



/**
  * @brief  Ovveride the _speex_fatal function of the speex library
  * @param  None
  * @retval : None
  */
void _speex_fatal(const char *str, const char *file, int line)
{
  while(1)
  {
  };
}





